<template>
    <div>
        <input type="file" :accept="accept" @change="handleChange" />
        <a-progress
            v-if="progressStatusCode !== '-1'"
            :percent="progress"
            :status="progressStatus[progressStatusCode]"
        ></a-progress>
    </div>
</template>
<script setup lang="ts">
import {
    uploadFile,
    uploadFileChunk,
    uploadFileChunkFinally,
} from '@/api/upload'
import { MAX_SIZE, CHUNK_SIZE } from '@/config/upload.config'
import { shallowReadonly, ref } from 'vue'

const progress = ref(0)
const progressStatusCode = ref<'-1' | '0' | '1' | '2'>('-1')

const progressStatus = shallowReadonly({
    0: 'active',
    1: 'success',
    2: 'exception',
})
type chunkFile = {
    file: Blob
    fileName?: string
    chunkIndex?: string
}
defineProps({
    modelValue: { type: String, default: '' },
    accept: { type: String, default: 'image/*' },
})
const emits = defineEmits(['update:modelValue'])
// const model = defineModel({default: null})
const handleChange = (event: Event) => {
    progress.value = 0
    progressStatusCode.value = '0'
    const file = (event.target as HTMLInputElement).files?.[0]
    if (!file) return
    if (file.size > MAX_SIZE) {
        postBigFile(file)
    } else {
        // 处理小文件
        const formData = new FormData()
        formData.append('file', file)
        uploadFile(formData, (event) => {
            console.log(event)
            progressStatusCode.value = '0'
            progress.value = Math.floor((event.progress as number) * 1000) / 10
        })
            .then((res) => {
                emits('update:modelValue', res.data)
                progressStatusCode.value = '1'
            })
            .catch(() => {
                progressStatusCode.value = '2'
            })
            .finally(() => {
                hideProgress()
            })
    }
}

// 等待一会儿 进度条消失
const hideProgress = (time: number = 1500) => {
    setTimeout(() => {
        progressStatusCode.value = '-1'
    }, time)
}

// 上传大文件
const postBigFile = (realFile: File) => {
    const chunks: Array<chunkFile> = splitChunk(realFile)
    getFileHash(chunks).then((hash) => {
        chunks.forEach((item, index) => {
            item.fileName = hash
            item.chunkIndex = index.toString()
        })
        let index = 0
        let successNum = 0
        const upload = () => {
            const { fileName, chunkIndex, file } = chunks[index++]
            const formData = new FormData()
            formData.append('file', file)
            formData.append('chunkName', fileName as string)
            formData.append('fileName', realFile.name)
            formData.append('chunkIndex', chunkIndex as string)
            uploadFileChunk(formData)
                .then(() => {
                    successNum++
                    progress.value =
                        Math.floor((successNum / chunks.length) * 1000) / 10
                    console.log(progress.value)
                })
                .finally(() => {
                    if (index < chunks.length) upload()
                    if (successNum >= chunks.length)
                        uploadFileChunkFinally({
                            fileName: realFile.name,
                            chunkName: fileName,
                        }).then(() => {
                            progress.value = 100
                            progressStatusCode.value = '1'
                            hideProgress()
                        })
                })
        }
        let thread = 3
        while (thread > 0) {
            thread--
            upload()
        }
    })
}
const splitChunk = (file: File) => {
    const fileChunkList: Array<chunkFile> = []
    let index = 0
    const chunkSize =
        file.size > 100 * 1024 * 1024 ? 10 * 1024 * 1024 : CHUNK_SIZE
    while (index * chunkSize <= file.size) {
        fileChunkList.push({
            file: file.slice(index * chunkSize, ++index * chunkSize),
        })
    }
    return fileChunkList
}

/* const getFileHash = (chunks: Array<chunkFile>) => {
    const spark = new sparkMd5.ArrayBuffer()
    const appendToSpark = (file: Blob) =>
        new Promise((resolve) => {
            const fileReader = new FileReader()
            fileReader.readAsArrayBuffer(file)
            fileReader.onload = (e) => {
                spark.append((e.target as FileReader).result as ArrayBuffer)
                resolve('')
                fileReader.abort()
            }
        })
    return new Promise<string>(async (resolve) => {
        for (let i = 0; i < chunks.length; i++) {
            const element = chunks[i].file
            await appendToSpark(element)
        }
        resolve(spark.end())
    })
} */
const getFileHash = (chunks: Array<chunkFile>) =>
    new Promise<string>((resolve) => {
        const fileHash = new Worker(new URL('@/fileHash.js', import.meta.url), {
            type: 'module',
        })
        fileHash.postMessage(chunks)
        fileHash.onmessage = (e: MessageEvent) => {
            resolve(e.data.result)
        }
    })
</script>
<style lang="scss" scoped>
.upload {
}
</style>
